home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / os2 / fst03f.zip / do_fat.c < prev    next >
C/C++ Source or Header  |  1996-04-16  |  43KB  |  1,404 lines

  1. /* do_fat.c -- FAT-specific code for fst
  2.    Copyright (c) 1995-1996 by Eberhard Mattes
  3.  
  4. This file is part of fst.
  5.  
  6. fst is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. fst is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with fst; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21.  
  22. /* TODO: Don't assume a sector size of 512 bytes. */
  23.  
  24. #include <os2.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <stdarg.h>
  28. #include <stddef.h>
  29. #include <string.h>
  30. #include "fst.h"
  31. #include "crc.h"
  32. #include "diskio.h"
  33. #include "fat.h"
  34.  
  35.  
  36. struct vfat
  37. {
  38.   char flag;
  39.   char unprintable;
  40.   BYTE total;
  41.   BYTE index;
  42.   BYTE checksum;
  43.   int start;
  44.   BYTE name[256+1];
  45. };
  46.  
  47. static ULONG first_sector;
  48. static ULONG total_sectors;
  49. static ULONG total_clusters;
  50. static ULONG sectors_per_cluster;
  51. static ULONG bytes_per_cluster;
  52. static ULONG sectors_per_fat;
  53. static ULONG number_of_fats;
  54. static ULONG root_entries;
  55. static ULONG root_sectors;
  56. static ULONG data_sector;
  57. static ULONG what_cluster;
  58. static USHORT **fats;
  59. static USHORT *fat;
  60.  
  61. static BYTE *usage_vector;      /* One byte per cluster, indicating usage */
  62. static const path_chain **path_vector; /* One path name chain per sector */
  63.  
  64. static BYTE find_comp[256];     /* Current component of `find_path' */
  65.  
  66. static char ea_ok;
  67. static ULONG ea_data_start;
  68. static ULONG ea_data_size;
  69. static ULONG ea_data_clusters;
  70. static USHORT ea_table1[240];   /* First table from `EA DATA. SF' */
  71. static USHORT *ea_table2;       /* Second table from `EA DATA. SF' */
  72. static ULONG ea_table2_entries;
  73. static BYTE *ea_usage;          /* One byte per cluster of `EA DATA. SF' */
  74.  
  75. #define CLUSTER_TO_SECTOR(c) (((c) - 2) * sectors_per_cluster + data_sector)
  76. #define SECTOR_TO_CLUSTER(s) (((s) - data_sector) / sectors_per_cluster + 2)
  77.  
  78.  
  79. /* Rotate right a byte by one bit. */
  80.  
  81. static INLINE BYTE rorb1 (BYTE b)
  82. {
  83.   return (b & 1) ? (b >> 1) | 0x80 : b >> 1;
  84. }
  85.  
  86.  
  87. /* Compare two file names pointed to by P1 and P2. */
  88.  
  89. static int compare_fname (const BYTE *p1, const BYTE *p2)
  90. {
  91.   for (;;)
  92.     {
  93.       if (*p1 == 0 && *p2 == 0)
  94.         return 0;
  95.       if (*p2 == 0)
  96.         return 1;
  97.       if (*p1 == 0)
  98.         return -1;
  99.       if (cur_case_map[*p1] > cur_case_map[*p2])
  100.         return 1;
  101.       if (cur_case_map[*p1] < cur_case_map[*p2])
  102.         return -1;
  103.       ++p1; ++p2;
  104.     }
  105. }
  106.  
  107.  
  108. /* Return a pointer to a string containing a formatted range of
  109.    cluster numbers.  Note that the pointer points to static memory; do
  110.    not use format_cluster_range() more than once in one expression! */
  111.  
  112. static const char *format_cluster_range (ULONG start, ULONG count)
  113. {
  114.   static char buf[60];
  115.  
  116.   if (count == 1)
  117.     sprintf (buf, "cluster %lu", start);
  118.   else
  119.     sprintf (buf, "%lu clusters %lu-%lu", count, start, start + count - 1);
  120.   return buf;
  121. }
  122.  
  123.  
  124. /* Return a pointer to a string containing a file time as string.
  125.    Note that the pointer points to static memory; do not use
  126.    format_time() more than once in one expression! */
  127.  
  128. static const char *format_time (unsigned t)
  129. {
  130.   static char buf[20];
  131.  
  132.   sprintf (buf, "%.2d:%.2d:%.2d",
  133.            (t >> 11) & 31, (t >> 5) & 63, (t & 31) << 1);
  134.   return buf;
  135. }
  136.  
  137.  
  138. /* Return a pointer to a string containing a file date as string.
  139.    Note that the pointer points to static memory; do not use
  140.    format_date() more than once in one expression! */
  141.  
  142. static const char *format_date (unsigned d)
  143. {
  144.   static char buf[20];
  145.  
  146.   sprintf (buf, "%d-%.2d-%.2d",
  147.            ((d >> 9) & 127) + 1980, (d >> 5) & 15, d & 31);
  148.   return buf;
  149. }
  150.  
  151.  
  152. /* Return the number of days in month M of year Y. */
  153.  
  154. static int days (int y, int m)
  155. {
  156.   static int month_len[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  157.  
  158.   if (m < 1 || m > 12)
  159.     return 0;
  160.   else if (m != 2)
  161.     return month_len[m-1];
  162.   else
  163.     return y % 4 != 0 ? 28 : y % 100 != 0 ? 29 : y % 400 != 0 ? 28 : 29;
  164. }
  165.  
  166.  
  167. /* Types of clusters. */
  168.  
  169. #define USE_EMPTY       0
  170. #define USE_FILE        1
  171. #define USE_DIR         2
  172.  
  173.  
  174. /* Return a pointer to a string containing a description of a cluster
  175.    type. */
  176.  
  177. static const char *cluster_usage (BYTE what)
  178. {
  179.   switch (what)
  180.     {
  181.     case USE_EMPTY:
  182.       return "empty";
  183.     case USE_DIR:
  184.       return "directory";
  185.     case USE_FILE:
  186.       return "file";
  187.     default:
  188.       return "INTERNAL_ERROR";
  189.     }
  190. }
  191.  
  192.  
  193. /* Use cluster CLUSTER for WHAT.  PATH points to a string naming the
  194.    object for which the cluster is used.  PATH points to the path name
  195.    chain for the file or directory.  Return FALSE if a cycle has been
  196.    detected. */
  197.  
  198. static int use_cluster (ULONG cluster, BYTE what, const path_chain *path)
  199. {
  200.   BYTE old;
  201.  
  202.   if (cluster >= total_clusters)
  203.     abort ();
  204.   old = usage_vector[cluster];
  205.   if (old != USE_EMPTY)
  206.     {
  207.       warning (1, "Cluster %lu usage conflict: %s vs. %s",
  208.                cluster, cluster_usage (usage_vector[cluster]),
  209.                cluster_usage (what));
  210.       if (path_vector != NULL && path_vector[cluster] != NULL)
  211.         warning_cont ("File 1: \"%s\"",
  212.                       format_path_chain (path_vector[cluster], NULL));
  213.       if (path != NULL)
  214.         warning_cont ("File 2: \"%s\"",
  215.                       format_path_chain (path, NULL));
  216.       return !(path != NULL && path == path_vector[cluster]);
  217.     }
  218.   else
  219.     {
  220.       usage_vector[cluster] = what;
  221.       if (path_vector != NULL)
  222.         path_vector[cluster] = path;
  223.       return TRUE;
  224.     }
  225. }
  226.  
  227.  
  228. static void dirent_warning (int level, const char *fmt, ULONG secno,
  229.                             const path_chain *path,
  230.                             const BYTE *name, ...) ATTR_PRINTF (2, 6);
  231.  
  232.  
  233. static USHORT *read_fat16 (DISKIO *d, ULONG secno)
  234. {
  235.   USHORT *fat;
  236.   ULONG sectors, clusters, i;
  237.  
  238.   clusters = total_clusters;
  239.   sectors = DIVIDE_UP (clusters * 2, 512);
  240.   if (sectors != sectors_per_fat)
  241.     warning (1, "Incorrect FAT size: %lu vs. %lu", sectors, sectors_per_fat);
  242.   fat = xmalloc (sectors * 512);
  243.   read_sec (d, fat, secno, sectors, TRUE);
  244.   for (i = 0; i < clusters; ++i)
  245.     fat[i] = USHORT_FROM_FS (fat[i]);
  246.   return fat;
  247. }
  248.  
  249.  
  250. static USHORT *read_fat12 (DISKIO *d, ULONG secno)
  251. {
  252.   USHORT *fat;
  253.   ULONG clusters, sectors, i, s, t;
  254.   USHORT c1, c2;
  255.   BYTE *raw;
  256.  
  257.   clusters = total_clusters;
  258.   sectors = DIVIDE_UP (clusters * 3, 512*2);
  259.   if (sectors != sectors_per_fat)
  260.     warning (1, "Incorrect FAT size: %lu vs. %lu", sectors, sectors_per_fat);
  261.   raw = xmalloc (sectors * 512 + 2);
  262.   read_sec (d, raw, secno, sectors, TRUE);
  263.   fat = xmalloc (clusters * 2 + 1);
  264.   s = 0;
  265.   for (i = 0; i < clusters; i += 2)
  266.     {
  267.       t = raw[s+0] | (raw[s+1] << 8) | (raw[s+2] << 16);
  268.       c1 = t & 0xfff;
  269.       if (c1 >= 0xff7)
  270.         c1 |= 0xf000;
  271.       c2 = (t >> 12) & 0xfff;
  272.       if (c2 >= 0xff7)
  273.         c2 |= 0xf000;
  274.       fat[i+0] = c1;
  275.       fat[i+1] = c2;
  276.       s += 3;
  277.     }
  278.   free (raw);
  279.   return fat;
  280. }
  281.  
  282.  
  283. static USHORT *read_fat (DISKIO *d, ULONG secno, ULONG fatno)
  284. {
  285.   if (a_what)
  286.     {
  287.       if (!what_cluster_flag && IN_RANGE (what_sector, secno, sectors_per_fat))
  288.         info ("Sector #%lu: Fat %lu (+%lu)\n", what_sector, fatno + 1,
  289.               what_sector - secno);
  290.     }
  291.   if (total_clusters - 2 > 4085)
  292.     return read_fat16 (d, secno);
  293.   else
  294.     return read_fat12 (d, secno);
  295. }
  296.  
  297.  
  298. static void do_fats (DISKIO *d)
  299. {
  300.   ULONG secno, i, j, k, free, bad;
  301.  
  302.   fats = xmalloc (number_of_fats * sizeof (*fats));
  303.   secno = first_sector;
  304.   for (i = 0; i < number_of_fats; ++i)
  305.     {
  306.       if (a_info)
  307.         info ("FAT %lu: